home *** CD-ROM | disk | FTP | other *** search
/ Visual Cafe 3 / Visual Cafe 3.ISO / Vcafe / JFC.bin / ScrollPaneLayout.java < prev    next >
Text File  |  1998-06-30  |  24KB  |  814 lines

  1. /*
  2.  * @(#)ScrollPaneLayout.java    1.23 98/04/01
  3.  * 
  4.  * Copyright (c) 1997 Sun Microsystems, Inc. All Rights Reserved.
  5.  * 
  6.  * This software is the confidential and proprietary information of Sun
  7.  * Microsystems, Inc. ("Confidential Information").  You shall not
  8.  * disclose such Confidential Information and shall use it only in
  9.  * accordance with the terms of the license agreement you entered into
  10.  * with Sun.
  11.  * 
  12.  * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
  13.  * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  14.  * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  15.  * PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES
  16.  * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
  17.  * THIS SOFTWARE OR ITS DERIVATIVES.
  18.  * 
  19.  */
  20.  
  21. package com.sun.java.swing;
  22.  
  23.  
  24. import com.sun.java.swing.border.*;
  25.  
  26. import java.awt.LayoutManager;
  27. import java.awt.Component;
  28. import java.awt.Container;
  29. import java.awt.Rectangle;
  30. import java.awt.Dimension;
  31. import java.awt.Insets;
  32. import java.io.Serializable;
  33.  
  34.  
  35. /**
  36.  * The layout manager used by JScrollPane.  JScrollPaneLayout is
  37.  * responsible for nine components: a viewport, two scrollbars,
  38.  * a row header, a column header, and four "corner" components.
  39.  * <p>
  40.  * Warning: serialized objects of this class will not be compatible with
  41.  * future swing releases.  The current serialization support is appropriate
  42.  * for short term storage or RMI between Swing1.0 applications.  It will
  43.  * not be possible to load serialized Swing1.0 objects with future releases
  44.  * of Swing.  The JDK1.2 release of Swing will be the compatibility
  45.  * baseline for the serialized form of Swing objects.
  46.  *
  47.  * @see JScrollPane
  48.  * @see JViewport
  49.  *
  50.  * @version 1.23 04/01/98
  51.  * @author unknown
  52.  */
  53. public class ScrollPaneLayout
  54.     implements LayoutManager, ScrollPaneConstants, Serializable
  55. {
  56.     /** The JViewport that displays the pane's contents */
  57.     protected JViewport viewport;
  58.     /** The vertical scrollbar */
  59.     protected JScrollBar vsb;
  60.     /** The horizontal scrollbar */
  61.     protected JScrollBar hsb;
  62.     /** The row-header component */
  63.     protected JViewport rowHead;
  64.     /** The column-header component */
  65.     protected JViewport colHead;
  66.     /** The component at the lower left corner */
  67.     protected Component lowerLeft;
  68.     /** The component at the lower right corner */
  69.     protected Component lowerRight;
  70.     /** The component at the upper left corner */
  71.     protected Component upperLeft;
  72.     /** The component at the upper right corner */
  73.     protected Component upperRight;
  74.  
  75.     /** 
  76.      * The display policy for the vertical scrollbar.
  77.      * Default = As Needed
  78.      */
  79.     protected int vsbPolicy = VERTICAL_SCROLLBAR_AS_NEEDED;
  80.     /**
  81.      * The display policy for the horizontal scrollbar.
  82.      * Default = As Needed
  83.      */
  84.     protected int hsbPolicy = HORIZONTAL_SCROLLBAR_AS_NEEDED;
  85.  
  86.  
  87.     /** 
  88.      * The method used to replace an existing component (if any) with a
  89.      * new one. Used to add each different kind of component to a JScrollPane,
  90.      * since there can be one and only one left corner, vertical scrollbar,
  91.      * and so on. So only one of each subcomponent is allowed, the old one
  92.      * is removed (if it exists) when a new one is added.
  93.      * 
  94.      * @param oldC the Component to replace
  95.      * @param newC the Component to add
  96.      */
  97.     protected Component addSingletonComponent(Component oldC, Component newC)
  98.     {
  99.     if ((oldC != null) && (oldC != newC)) {
  100.         oldC.getParent().remove(oldC);
  101.     }
  102.     return newC;
  103.     }
  104.  
  105.  
  106.     /**
  107.      * Adds the specified component to the layout, identifying it
  108.      * as one of:<ul>
  109.      * <li>ScrollPaneConstants.VIEWPORT
  110.      * <li>ScrollPaneConstants.VERTICAL_SCROLLBAR
  111.      * <li>ScrollPaneConstants.HORIZONTAL_SCROLLBAR
  112.      * <li>ScrollPaneConstants.ROW_HEADER
  113.      * <li>ScrollPaneConstants.COLUMN_HEADER
  114.      * <li>ScrollPaneConstants.LOWER_LEFT_CORNER
  115.      * <li>ScrollPaneConstants.LOWER_RIGHT_CORNER
  116.      * <li>ScrollPaneConstants.UPPER_LEFT_CORNER
  117.      * <li>ScrollPaneConstants.UPPER_RIGHT_CORNER
  118.      * </ul>
  119.      *
  120.      * @param s the component identifier
  121.      * @param comp the the component to be added
  122.      */
  123.     public void addLayoutComponent(String s, Component c) 
  124.     {
  125.     if (s.equals(VIEWPORT)) {
  126.         viewport = (JViewport)addSingletonComponent(viewport, c);
  127.     }
  128.     else if (s.equals(VERTICAL_SCROLLBAR)) {
  129.         vsb = (JScrollBar)addSingletonComponent(vsb, c);
  130.     }
  131.     else if (s.equals(HORIZONTAL_SCROLLBAR)) {
  132.         hsb = (JScrollBar)addSingletonComponent(hsb, c);
  133.     }
  134.     else if (s.equals(ROW_HEADER)) {
  135.         rowHead = (JViewport)addSingletonComponent(rowHead, c);
  136.     }
  137.     else if (s.equals(COLUMN_HEADER)) {
  138.         colHead = (JViewport)addSingletonComponent(colHead, c);
  139.     }
  140.     else if (s.equals(LOWER_LEFT_CORNER)) {
  141.         lowerLeft = addSingletonComponent(lowerLeft, c);
  142.     }
  143.     else if (s.equals(LOWER_RIGHT_CORNER)) {
  144.         lowerRight = addSingletonComponent(lowerRight, c);
  145.     }
  146.     else if (s.equals(UPPER_LEFT_CORNER)) {
  147.         upperLeft = addSingletonComponent(upperLeft, c);
  148.     }
  149.     else if (s.equals(UPPER_RIGHT_CORNER)) {
  150.         upperRight = addSingletonComponent(upperRight, c);
  151.     }
  152.     else {
  153.         throw new IllegalArgumentException("invalid layout key " + s);
  154.     }
  155.     }
  156.  
  157.  
  158.     /**
  159.      * Removes the specified component from the layout.
  160.      *   
  161.      * @param comp the component to remove
  162.      */
  163.     public void removeLayoutComponent(Component c) 
  164.     {
  165.     if (c == viewport) {
  166.         viewport = null;
  167.     }
  168.     else if (c == vsb) {
  169.         vsb = null;
  170.     }
  171.     else if (c == hsb) {
  172.         hsb = null;
  173.     }
  174.     else if (c == rowHead) {
  175.         rowHead = null;
  176.     }
  177.     else if (c == colHead) {
  178.         colHead = null;
  179.     }
  180.     else if (c == lowerLeft) {
  181.         lowerLeft = null;
  182.     }
  183.     else if (c == lowerRight) {
  184.         lowerLeft = null;
  185.     }
  186.     else if (c == upperLeft) {
  187.         upperLeft = null;
  188.     }
  189.     else if (c == upperRight) {
  190.         upperRight = null;
  191.     }
  192.     }
  193.  
  194.  
  195.     /**
  196.      * Returns the vertical scrollbar-display policy.
  197.      *
  198.      * @return an int giving the display policy
  199.      * @see #setVerticalScrollBarPolicy
  200.      */
  201.     public int getVerticalScrollBarPolicy() {
  202.     return vsbPolicy;
  203.     }
  204.  
  205.     /**
  206.      * Returns the vertical scrollbar-display policy, where the
  207.      * options are:<ul>
  208.      * <li>ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED
  209.      * <li>ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER
  210.      * <li>ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS
  211.      * </ul>
  212.      *
  213.      * @param x an int giving the display policy
  214.      */
  215.     public void setVerticalScrollBarPolicy(int x) {
  216.     switch (x) {
  217.     case VERTICAL_SCROLLBAR_AS_NEEDED:
  218.     case VERTICAL_SCROLLBAR_NEVER:
  219.     case VERTICAL_SCROLLBAR_ALWAYS:
  220.             vsbPolicy = x;
  221.         break;
  222.     default:
  223.         throw new IllegalArgumentException("invalid verticalScrollBarPolicy");
  224.     }
  225.     }
  226.  
  227.  
  228.     /**
  229.      * Returns the horizontal scrollbar-display policy.
  230.      *
  231.      * @return an int giving the display policy
  232.      * @see #setHorizontalScrollBarPolicy
  233.      */
  234.     public int getHorizontalScrollBarPolicy() {
  235.     return hsbPolicy;
  236.     }
  237.  
  238.     /**
  239.      * Returns the horizontal scrollbar-display policy, where the
  240.      * options are:<ul>
  241.      * <li>ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED
  242.      * <li>ScrollPaneConstants.HOTRIZONTAL_SCROLLBAR_NEVER
  243.      * <li>ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS
  244.      * </ul>
  245.      *
  246.      * @param x an int giving the display policy
  247.      */
  248.     public void setHorizontalScrollBarPolicy(int x) {
  249.     switch (x) {
  250.     case HORIZONTAL_SCROLLBAR_AS_NEEDED:
  251.     case HORIZONTAL_SCROLLBAR_NEVER:
  252.     case HORIZONTAL_SCROLLBAR_ALWAYS:
  253.             hsbPolicy = x;
  254.         break;
  255.     default:
  256.         throw new IllegalArgumentException("invalid horizontalScrollBarPolicy");
  257.     }
  258.     }
  259.  
  260.  
  261.     /**
  262.      * Returns the view port object.
  263.      *
  264.      * @return the JViewport object that displays the scrollable contents
  265.      */
  266.     public JViewport getViewport() {
  267.     return viewport;
  268.     }
  269.  
  270.  
  271.     /**
  272.      * Returns the horizontal scrollbar.
  273.      *
  274.      * @return the JScrollbar object that handles horizontal scrolling
  275.      */
  276.     public JScrollBar getHorizontalScrollBar() {
  277.     return hsb;
  278.     }
  279.  
  280.     /**
  281.      * Returns the vertical scrollbar.
  282.      *
  283.      * @return the JScrollbar object that handles vertical scrolling
  284.      */
  285.     public JScrollBar getVerticalScrollBar() {
  286.     return vsb;
  287.     }
  288.  
  289.  
  290.     /**
  291.      * Returns the row header component.
  292.      *
  293.      * @return the JViewport object that is the row header
  294.      */
  295.     public JViewport getRowHeader() {
  296.     return rowHead;
  297.     }
  298.  
  299.     /**
  300.      * Returns the column header component.
  301.      *
  302.      * @return the JViewport object that is the column header
  303.      */
  304.     public JViewport getColumnHeader() {
  305.     return colHead;
  306.     }
  307.  
  308.     /**
  309.      * Returns the component at the specified corner, where the
  310.      * corner specification is one of:<ul>
  311.      * <li>ScrollPaneConstants.LOWER_LEFT_CORNER
  312.      * <li>ScrollPaneConstants.LOWER_RIGHT_CORNER
  313.      * <li>ScrollPaneConstants.UPPER_LEFT_CORNER
  314.      * <li>ScrollPaneConstants.UPPER_RIGHT_CORNER
  315.      * </ul>
  316.      *
  317.      * @return the Component at the specified corner
  318.      */
  319.     public Component getCorner(String key) {
  320.     if (key.equals(LOWER_LEFT_CORNER)) {
  321.         return lowerLeft;
  322.     }
  323.     else if (key.equals(LOWER_RIGHT_CORNER)) {
  324.         return lowerRight;
  325.     }
  326.     else if (key.equals(UPPER_LEFT_CORNER)) {
  327.         return upperLeft;
  328.     }
  329.     else if (key.equals(UPPER_RIGHT_CORNER)) {
  330.         return upperRight;
  331.     }
  332.     else {
  333.         return null;
  334.     }
  335.     }
  336.  
  337.  
  338.     /** 
  339.      * The preferred size of a ScrollPane is the size of the insets,
  340.      * plus the preferred size of the viewport, plus the preferred size of 
  341.      * the visible headers, plus the preferred size of the scrollbars
  342.      * that will appear given the current view and the current
  343.      * scrollbar displayPolicies.  
  344.      * 
  345.      * @param parent the Container that will be laid out
  346.      * @return a Dimension object specifying the preferred size of the 
  347.      *         viewport and any scrollbars.
  348.      * @see ViewportLayout
  349.      * @see LayoutManager
  350.      */
  351.     public Dimension preferredLayoutSize(Container parent) 
  352.     {
  353.     Insets insets = parent.getInsets();
  354.     int prefWidth = insets.left + insets.right;
  355.     int prefHeight = insets.top + insets.bottom;
  356.  
  357.     /* Note that viewport.getViewSize() is equivalent to 
  358.      * viewport.getView().getPreferredSize() modulo a null
  359.      * view or a view whose size was explicitly set.
  360.      */
  361.  
  362.     Dimension extentSize = null;
  363.     Dimension viewSize = null;
  364.     Component view = null;
  365.  
  366.     if (viewport !=  null) {
  367.         extentSize = viewport.getPreferredSize();
  368.         viewSize = viewport.getViewSize();
  369.         view = viewport.getView();
  370.     }
  371.  
  372.     /* If there's a viewport add its preferredSize.
  373.      */
  374.  
  375.     if (extentSize != null) {
  376.         prefWidth += extentSize.width;
  377.         prefHeight += extentSize.height;
  378.     }
  379.  
  380.     /* If there's a JScrollPane.viewportBorder, add its insets.
  381.      */
  382.  
  383.     Border viewportBorder = ((JScrollPane)parent).getViewportBorder();
  384.     if (viewportBorder != null) {
  385.         Insets vpbInsets = viewportBorder.getBorderInsets(parent);
  386.         prefWidth += vpbInsets.left + vpbInsets.right;
  387.         prefHeight += vpbInsets.top + vpbInsets.bottom;
  388.     }
  389.  
  390.     /* If a header exists and it's visible, factor its
  391.      * preferred size in.
  392.      */
  393.  
  394.     if ((rowHead != null) && rowHead.isVisible()) {
  395.         prefWidth += rowHead.getPreferredSize().width;
  396.     }
  397.  
  398.     if ((colHead != null) && colHead.isVisible()) {
  399.         prefHeight += colHead.getPreferredSize().height;
  400.     }
  401.  
  402.     /* If a scrollbar is going to appear, factor its preferred size in.
  403.      * If the scrollbars policy is AS_NEEDED, this can be a little
  404.      * tricky:
  405.      * 
  406.      * - If the view is a Scrollable then scrollableTracksViewportWidth
  407.      * and scrollableTracksViewportHeight can be used to effectively 
  408.      * disable scrolling (if they're true) in their respective dimensions.
  409.      * 
  410.      * - Assuming that a scrollbar hasn't been disabled by the 
  411.      * previous constraint, we need to decide if the scrollbar is going 
  412.      * to appear to correctly compute the JScrollPanes preferred size.
  413.      * To do this we compare the preferredSize of the viewport (the 
  414.      * extentSize) to the preferredSize of the view.  Although we're
  415.      * not responsible for laying out the view we'll assume that the 
  416.      * JViewport will always give it its preferredSize.
  417.      */
  418.  
  419.     if ((vsb != null) && (vsbPolicy != VERTICAL_SCROLLBAR_NEVER)) {
  420.         if (vsbPolicy == VERTICAL_SCROLLBAR_ALWAYS) {
  421.         prefWidth += vsb.getPreferredSize().width;
  422.         }
  423.         else if ((viewSize != null) && (extentSize != null)) {
  424.         boolean canScroll = true;
  425.         if (view instanceof Scrollable) {
  426.             canScroll = !((Scrollable)view).getScrollableTracksViewportHeight();
  427.         }
  428.         if (canScroll && (viewSize.height > extentSize.height)) {
  429.             prefWidth += vsb.getPreferredSize().width;
  430.         }
  431.         }
  432.     }
  433.  
  434.     if ((hsb != null) && (hsbPolicy != HORIZONTAL_SCROLLBAR_NEVER)) {
  435.         if (hsbPolicy == HORIZONTAL_SCROLLBAR_ALWAYS) {
  436.         prefHeight += hsb.getPreferredSize().height;
  437.         }
  438.         else if ((viewSize != null) && (extentSize != null)) {
  439.         boolean canScroll = true;
  440.         if (view instanceof Scrollable) {
  441.             canScroll = !((Scrollable)view).getScrollableTracksViewportWidth();
  442.         }
  443.         if (canScroll && (viewSize.width > extentSize.width)) {
  444.             prefHeight += hsb.getPreferredSize().height;
  445.         }
  446.         }
  447.     }
  448.  
  449.     return new Dimension(prefWidth, prefHeight);
  450.     }
  451.  
  452.  
  453.     /** 
  454.      * The minimum size of a ScrollPane is the size of the insets 
  455.      * plus minimum size of the viewport, plus the scrollpane's
  456.      * viewportBorder insets, plus the minimum size 
  457.      * of the visible headers, plus the minimum size of the 
  458.      * scrollbars whose displayPolicy isn't NEVER.
  459.      * 
  460.      * @param parent the Container that will be laid out
  461.      * @return a Dimension object specifying the minimum size
  462.      */
  463.     public Dimension minimumLayoutSize(Container parent) 
  464.     {
  465.     Insets insets = parent.getInsets();
  466.     int minWidth = insets.left + insets.right;
  467.     int minHeight = insets.top + insets.bottom;
  468.     
  469.     /* If there's a viewport add its minimumSize.
  470.      */
  471.     
  472.     if (viewport != null) {
  473.         Dimension size = viewport.getMinimumSize();
  474.         minWidth += size.width;
  475.         minHeight += size.height;
  476.     }
  477.  
  478.     /* If there's a JScrollPane.viewportBorder, add its insets.
  479.      */
  480.  
  481.     Border viewportBorder = ((JScrollPane)parent).getViewportBorder();
  482.     if (viewportBorder != null) {
  483.         Insets vpbInsets = viewportBorder.getBorderInsets(parent);
  484.         minWidth += vpbInsets.left + vpbInsets.right;
  485.         minHeight += vpbInsets.top + vpbInsets.bottom;
  486.     }
  487.  
  488.     /* If a header exists and it's visible, factor its
  489.      * minimum size in.
  490.      */
  491.  
  492.     if ((rowHead != null) && rowHead.isVisible()) {
  493.         Dimension size = rowHead.getMinimumSize();
  494.         minWidth += size.width;
  495.         minHeight = Math.max(minHeight, size.height);
  496.     }
  497.  
  498.     if ((colHead != null) && colHead.isVisible()) {
  499.         Dimension size = colHead.getMinimumSize();
  500.         minWidth = Math.max(minWidth, size.width);
  501.         minHeight += size.height;
  502.     }
  503.  
  504.     /* If a scrollbar might appear, factor its minimum
  505.      * size in.
  506.      */
  507.  
  508.     if ((vsb != null) && (vsbPolicy != VERTICAL_SCROLLBAR_NEVER)) {
  509.         Dimension size = vsb.getMinimumSize();
  510.         minWidth += size.width;
  511.         minHeight = Math.max(minHeight, size.height);
  512.     }
  513.  
  514.     if ((hsb != null) && (hsbPolicy != VERTICAL_SCROLLBAR_NEVER)) {
  515.         Dimension size = hsb.getMinimumSize();
  516.         minWidth = Math.max(minWidth, size.width);
  517.         minHeight += size.height;
  518.     }
  519.  
  520.     return new Dimension(minWidth, minHeight);
  521.     }
  522.  
  523.  
  524.     /** 
  525.      * Layout the scrollpane according to the following constraints:
  526.      * <ul>
  527.      * <li> The row header, if present and visible, gets its preferred
  528.      * height and the viewports width.
  529.      * 
  530.      * <li> The column header, if present and visible, gets its preferred
  531.      * width and the viewports height.
  532.      * 
  533.      * <li> If a vertical scrollbar is needed, i.e. if the viewports extent
  534.      * height is smaller than its view height or if the displayPolicy
  535.      * is ALWAYS, it's treated like the row header wrt it's dimensions and
  536.      * it's made visible.
  537.      * 
  538.      * <li> If a horizontal scrollbar is needed it's treated like the
  539.      * column header (and see the vertical scrollbar item).
  540.      * 
  541.      * <li> If the scrollpane has a non-null viewportBorder, then space
  542.      * is allocated for that.
  543.      * 
  544.      * <li> The viewport gets the space available after accounting for
  545.      * the previous constraints.
  546.      * 
  547.      * <li> The corner components, if provided, are aligned with the 
  548.      * ends of the scrollbars and headers. If there's a vertical
  549.      * scrollbar the right corners appear, if there's a horizontal
  550.      * scrollbar the lower corners appear, a row header gets left
  551.      * corners and a column header gets upper corners.
  552.      * </ul>
  553.      *
  554.      * @param parent the Container to lay out
  555.      */
  556.     public void layoutContainer(Container parent) 
  557.     {
  558.     Rectangle availR = new Rectangle(parent.getSize());
  559.  
  560.     Insets insets = parent.getInsets();
  561.     availR.x = insets.left;
  562.     availR.y = insets.top;
  563.     availR.width -= insets.left + insets.right;
  564.     availR.height -= insets.top + insets.bottom;
  565.  
  566.  
  567.     /* If there's a visible column header remove the space it 
  568.      * needs from the top of availR.  The column header is treated 
  569.      * as if it were fixed height, arbitrary width.
  570.      */
  571.  
  572.     Rectangle colHeadR = new Rectangle(0, availR.y, 0, 0);
  573.  
  574.     if ((colHead != null) && (colHead.isVisible())) {
  575.         int colHeadHeight = colHead.getPreferredSize().height;
  576.         colHeadR.height = colHeadHeight; 
  577.         availR.y += colHeadHeight;
  578.         availR.height -= colHeadHeight;
  579.     }
  580.  
  581.     /* If there's a visible row header remove the space it needs
  582.      * from the left of availR.  The row header is treated 
  583.      * as if it were fixed width, arbitrary height.
  584.      */
  585.  
  586.     Rectangle rowHeadR = new Rectangle(availR.x, 0, 0, 0);
  587.     
  588.     if ((rowHead != null) && (rowHead.isVisible())) {
  589.         int rowHeadWidth = rowHead.getPreferredSize().width;
  590.         rowHeadR.width = rowHeadWidth;
  591.         availR.x += rowHeadWidth;
  592.         availR.width -= rowHeadWidth;
  593.     }
  594.  
  595.     /* If there's a JScrollPane.viewportBorder, remove the
  596.      * space it occupies for availR.
  597.      */
  598.  
  599.     Border viewportBorder = ((JScrollPane)parent).getViewportBorder();
  600.     Insets vpbInsets;
  601.     if (viewportBorder != null) {
  602.         vpbInsets = viewportBorder.getBorderInsets(parent);
  603.         availR.x += vpbInsets.left;
  604.         availR.y += vpbInsets.top;
  605.         availR.width -= vpbInsets.left + vpbInsets.right;
  606.         availR.height -= vpbInsets.top + vpbInsets.bottom;
  607.     }
  608.     else {
  609.         vpbInsets = new Insets(0,0,0,0);
  610.     }
  611.  
  612.     colHeadR.x = availR.x;
  613.     rowHeadR.y = availR.y;
  614.  
  615.     /* At this point availR is the space available for the viewport
  616.      * and scrollbars and the rowHeadR colHeadR rectangles are correct
  617.      * except for their width and height respectively.  Once we're 
  618.      * through computing the dimensions  of these three parts we can 
  619.      * go back and set the dimensions of rowHeadR.width, colHeadR.height, 
  620.      * and the bounds for the corners.
  621.      * 
  622.          * We'll decide about putting up scrollbars by comparing the 
  623.          * viewport views preferred size with the viewports extent
  624.      * size (generally just its size).  Using the preferredSize is
  625.      * reasonable because layout proceeds top down - so we expect
  626.      * the viewport to be layed out next.  And it will change the
  627.      * resize the view to its preferred size or bigger.  It's potentially 
  628.      * bigger if the views Scrollable.getViewTracksViewport{Width,Height}
  629.      * returns true.
  630.      */
  631.  
  632.     Component view = (viewport != null) ? viewport.getView() : null;
  633.     Dimension viewSize =  
  634.         (view != null) ? view.getPreferredSize() 
  635.                            : new Dimension(0,0);
  636.  
  637.     Dimension extentSize = 
  638.         (viewport != null) ? viewport.toViewCoordinates(availR.getSize()) 
  639.                            : new Dimension(0,0);
  640.  
  641.     /* If there's a vertical scrollbar and we need one, allocate
  642.      * space for it (we'll make it visible later). A vertical 
  643.      * scrollbar is considered to be fixed width, arbitrary height.
  644.      */
  645.  
  646.     Rectangle vsbR = new Rectangle(0, availR.y - vpbInsets.top, 0, 0);
  647.     boolean vsbNeeded = 
  648.         (vsbPolicy == VERTICAL_SCROLLBAR_ALWAYS) ||
  649.         ((viewSize.height > extentSize.height) && 
  650.          (vsbPolicy == VERTICAL_SCROLLBAR_AS_NEEDED));
  651.  
  652.     if ((vsb != null) && vsbNeeded) {
  653.         int vsbWidth = vsb.getPreferredSize().width;
  654.         availR.width -= vsbWidth;
  655.         vsbR.x = availR.x + availR.width + vpbInsets.right;
  656.         vsbR.width = vsbWidth;
  657.     }
  658.     
  659.     /* If there's a horizontal scrollbar and we need one, allocate
  660.      * space for it (we'll make it visible later). A horizontal 
  661.      * scrollbar is considered to be fixed height, arbitrary width.
  662.      */
  663.  
  664.     Rectangle hsbR = new Rectangle(availR.x - vpbInsets.left, 0, 0, 0);
  665.     boolean hsbNeeded = 
  666.         (hsbPolicy == HORIZONTAL_SCROLLBAR_ALWAYS) || 
  667.         ((viewSize.width > extentSize.width) && 
  668.          (hsbPolicy == HORIZONTAL_SCROLLBAR_AS_NEEDED));
  669.  
  670.     if ((hsb != null) && hsbNeeded) {
  671.         int hsbHeight = hsb.getPreferredSize().height;
  672.         availR.height -= hsbHeight;
  673.         hsbR.y = availR.y + availR.height + vpbInsets.bottom;
  674.         hsbR.height = hsbHeight;
  675.     
  676.         /* If we added the horizontal scrollbar then we've implicitly 
  677.          * reduced  the vertical space available to the viewport. 
  678.          * As a consequence we may have to add the vertical scrollbar, 
  679.          * if that hasn't been done so already.  Ofcourse we
  680.          * don't bother with any of this if the vsbPolicy is NEVER.
  681.          */
  682.         if ((vsb != null) && !vsbNeeded && (vsbPolicy != VERTICAL_SCROLLBAR_NEVER)) {
  683.         extentSize = viewport.toViewCoordinates(availR.getSize());
  684.         vsbNeeded = viewSize.height > extentSize.height;
  685.  
  686.         if (vsbNeeded) {
  687.             int vsbWidth = vsb.getPreferredSize().width;
  688.             availR.width -= vsbWidth;
  689.             vsbR.x = availR.x + availR.width + vpbInsets.right;
  690.             vsbR.width = vsbWidth;
  691.         }
  692.         }
  693.     }
  694.  
  695.     /* We now have the final size of the viewport: availR.
  696.      * Now fixup the header and scrollbar widths/heights.
  697.      */
  698.     
  699.     vsbR.height = availR.height + vpbInsets.top + vpbInsets.bottom;
  700.     hsbR.width = availR.width + vpbInsets.left + vpbInsets.right;
  701.     rowHeadR.height = availR.height;
  702.     colHeadR.width = availR.width;
  703.  
  704.     /* Set the bounds of all nine components.  The scrollbars
  705.      * are made invisible if they're not needed.
  706.      */
  707.     
  708.     if (viewport != null) {
  709.         viewport.setBounds(availR);
  710.     }
  711.  
  712.     if (rowHead != null) {
  713.         rowHead.setBounds(rowHeadR);
  714.     }
  715.  
  716.     if (colHead != null) {
  717.         colHead.setBounds(colHeadR);
  718.     }
  719.  
  720.     if (vsb != null) {
  721.         if (vsbNeeded) {
  722.         vsb.setVisible(true);
  723.         vsb.setBounds(vsbR);
  724.         }
  725.         else {
  726.         vsb.setVisible(false);
  727.         }
  728.     }
  729.  
  730.     if (hsb != null) {
  731.         if (hsbNeeded) {
  732.         hsb.setVisible(true);
  733.         hsb.setBounds(hsbR);
  734.         }
  735.         else {
  736.         hsb.setVisible(false);
  737.         }
  738.     }
  739.  
  740.     if (lowerLeft != null) {
  741.         lowerLeft.setBounds(rowHeadR.x, hsbR.y, rowHeadR.width, hsbR.height);
  742.     }
  743.  
  744.     if (lowerRight != null) {
  745.         lowerRight.setBounds(vsbR.x, hsbR.y, vsbR.width, hsbR.height);
  746.     }
  747.  
  748.     if (upperLeft != null) {
  749.         upperLeft.setBounds(rowHeadR.x, colHeadR.y, rowHeadR.width, colHeadR.height);
  750.     }
  751.  
  752.     if (upperRight != null) {
  753.         upperRight.setBounds(vsbR.x, colHeadR.y, vsbR.width, colHeadR.height);
  754.     }
  755.     }
  756.     
  757.     /** 
  758.      * Returns the bounds of the border around the specified scroll pane's 
  759.      * viewport.
  760.      *
  761.      * @return a Rectangle containing the size and position of the viewport
  762.      *         border
  763.      */
  764.     public Rectangle getViewportBorderBounds(JScrollPane sp)
  765.     {
  766.     Rectangle borderR = new Rectangle(sp.getSize());
  767.  
  768.     Insets insets = sp.getInsets();
  769.     borderR.x = insets.left;
  770.     borderR.y = insets.top;
  771.     borderR.width -= insets.left + insets.right;
  772.     borderR.height -= insets.top + insets.bottom;
  773.  
  774.  
  775.     /* If there's a visible column header remove the space it 
  776.      * needs from the top of borderR.  
  777.      */
  778.  
  779.     if ((colHead != null) && (colHead.isVisible())) {
  780.         int colHeadHeight = colHead.getHeight();
  781.         borderR.y += colHeadHeight;
  782.         borderR.height -= colHeadHeight;
  783.     }
  784.  
  785.     /* If there's a visible row header remove the space it needs
  786.      * from the left of borderR.  
  787.      */
  788.  
  789.     if ((rowHead != null) && (rowHead.isVisible())) {
  790.         int rowHeadWidth = rowHead.getWidth();
  791.         borderR.x += rowHeadWidth;
  792.         borderR.width -= rowHeadWidth;
  793.     }
  794.  
  795.     /* If there's a visible vertical scrollbar remove the space it needs
  796.      * from the width of borderR.  
  797.      */
  798.  
  799.     if ((vsb != null) && (vsb.isVisible())) {
  800.         borderR.width -= vsb.getWidth();
  801.     }
  802.  
  803.     /* If there's a visible horizontal scrollbar remove the space it needs
  804.      * from the height of borderR.  
  805.      */
  806.  
  807.     if ((hsb != null) && (hsb.isVisible())) {
  808.         borderR.height -= hsb.getHeight();
  809.     }
  810.  
  811.     return borderR;
  812.     }
  813. }
  814.